Using the OS GeoDataViz Toolkit to assist with styling of location data insights.

OS GeoDataViz Toolkit

The OS GeoDataViz (GDV) Toolkit provides a set of resources to help you communicate your data effectively through the design of compelling visuals.

The toolkit provides a series of colour palettes which provide a great starting point for thematic map design. The palettes can be programmatically accessed via JSON copy in the repo.

Qualitative Styling

When styling qualitative (categorical) data we need to be mindful of the number of distinct classes. The GDV qualitative colours supports up to eight classes. Beyond approximately 10 classes it becomes very difficult to design a palette that preserves the separation between colours allowing clear class identification.


library(sf)
library(tmap)
library(httr)
library(jsonlite)

Create sf data frame from GeoPackage (GPKG)

Combine the file reading and spatial subsetting by bounding box.

# Creating bounding box
bbox <- st_bbox(c(xmin = 503568.1996, 
                  xmax = 561957.4962, 
                  ymin = 155850.7975, 
                  ymax = 200933.9026), 
                crs = st_crs(27700))

# Convert into a 'geometry'
bbox <- st_as_sfc(bbox)

# Create an sf data.frame object from the Greenspace file
# Can do subset using bounding box at same time as read in
osogs <- st_read('../../data/ordnance-survey/os-open-greenspace-gb.gpkg',
                 layer = 'greenspace_site',
                 wkt_filter = st_as_text(bbox))  # Subset the data to Greater London
Reading layer `greenspace_site' from data source 
  `/cloud/project/data/ordnance-survey/os-open-greenspace-gb.gpkg' using driver `GPKG'
Simple feature collection with 12529 features and 6 fields
Geometry type: MULTIPOLYGON
Dimension:     XY
Bounding box:  xmin: 502292 ymin: 155102 xmax: 562996.9 ymax: 207036.4
Projected CRS: OSGB 1936 / British National Grid

Subset data frame by function

Reduce the number of function categories to support qualitative styling colour palette integration.

# Subset data frame by function, excluding 'Play Space' and 'Tennis Court'
osogs_filtered <- osogs[!osogs$function. %in% c('Play Space', 'Tennis Court'), ]
# List unique function values
unique(osogs_filtered$function.)
[1] "Allotments Or Community Growing Spaces" "Public Park Or Garden"                 
[3] "Religious Grounds"                      "Playing Field"                         
[5] "Bowling Green"                          "Cemetery"                              
[7] "Other Sports Facility"                  "Golf Course"                           
# Count number of unique function values
length(unique(osogs_filtered$function.))
[1] 8

OS Maps API ZXY resource

# OS Maps API layer
# Example uses Light Style in Web Mercator (EPSG:3857) projection
layer <- 'Light_3857'

# OS Data Hub project API key
key <- '7UTXMMWsGjjIzcBmLdAGnMO6WEAQi9Ng'
# Define the tile server parameters
url <- paste0('https://api.os.uk/maps/raster/v1/zxy/', layer,
              '/{z}/{x}/{y}.png?key=', key)

OS GeoDataViz colour palettes

The OS GeoDataViz toolkit provides qualitative, sequential, and diverging colour palettes to support GDV applications.

# GDV colour palettes JSON file
gdv <- 'https://raw.githubusercontent.com/OrdnanceSurvey/GeoDataViz-Toolkit/master/Colours/GDV-colour-palettes-v0.7.json'

# Make HTTP GET request and decode JSON
gdv_json <- GET(url = gdv)
gdv_json <- fromJSON(content(gdv_json))

# Get colour hex values
gdv_qual <- unlist(gdv_json$qualitative$lookup)

# Show an example of the colours
(image(1:length(gdv_qual), 1, as.matrix(1:length(gdv_qual)), 
      col = gdv_qual,
      xlab="", ylab = "", xaxt = "n", yaxt = "n", bty = "n"))
NULL

Plot data frame ontop of interactive map

Employ categorical styling via OS GeoDataViz (GDV) qualitative colour palette.

# Generate a basic plot of the features
p <- tm_shape(osogs_filtered) +
      tm_polygons('function.', 
                  pal = gdv_qual,
                  popup.vars = FALSE)
# Change plotting mode from static to interactive
tmap_mode('view')
tmap mode set to interactive viewing
# Combine the features and base map
final_plot <- p +
                tm_basemap(server = url)

final_plot
Warning: palette colors names missing for Allotments Or Community Growing Spaces, Bowling Green, Cemetery, Golf Course, Other Sports Facility, Playing Field, Public Park Or Garden, Religious Grounds. Therefore, palette color names will be ignored
# Change back to the static plotting mode
tmap_mode('plot')
tmap mode set to plotting
LS0tCnRpdGxlOiAiMDEgT1MgR2VvRGF0YVZpeiBUb29sa2l0IgpvdXRwdXQ6IGh0bWxfbm90ZWJvb2sKLS0tCgpVc2luZyB0aGUgT1MgR2VvRGF0YVZpeiBUb29sa2l0IHRvIGFzc2lzdCB3aXRoIHN0eWxpbmcgb2YgbG9jYXRpb24gZGF0YQppbnNpZ2h0cy4KCiMjIE9TIEdlb0RhdGFWaXogVG9vbGtpdAoKVGhlIE9TIFtHZW9EYXRhVml6IChHRFYpClRvb2xraXRdKGh0dHBzOi8vZ2l0aHViLmNvbS9PcmRuYW5jZVN1cnZleS9HZW9EYXRhVml6LVRvb2xraXQpIHByb3ZpZGVzIGEgc2V0IG9mCnJlc291cmNlcyB0byBoZWxwIHlvdSBjb21tdW5pY2F0ZSB5b3VyIGRhdGEgZWZmZWN0aXZlbHkgdGhyb3VnaCB0aGUgZGVzaWduIG9mCmNvbXBlbGxpbmcgdmlzdWFscy4KClRoZSB0b29sa2l0IHByb3ZpZGVzIGEgc2VyaWVzIG9mIGNvbG91ciBwYWxldHRlcyB3aGljaCBwcm92aWRlIGEgZ3JlYXQgc3RhcnRpbmcKcG9pbnQgZm9yIHRoZW1hdGljIG1hcCBkZXNpZ24uIFRoZSBwYWxldHRlcyBjYW4gYmUgcHJvZ3JhbW1hdGljYWxseSBhY2Nlc3NlZCB2aWEKSlNPTiBjb3B5IGluIHRoZSByZXBvLgoKIyMgUXVhbGl0YXRpdmUgU3R5bGluZwoKV2hlbiBzdHlsaW5nIHF1YWxpdGF0aXZlIChjYXRlZ29yaWNhbCkgZGF0YSB3ZSBuZWVkIHRvIGJlIG1pbmRmdWwgb2YgdGhlIG51bWJlcgpvZiBkaXN0aW5jdCBjbGFzc2VzLiBUaGUgR0RWIHF1YWxpdGF0aXZlIGNvbG91cnMgc3VwcG9ydHMgdXAgdG8gZWlnaHQgY2xhc3Nlcy4KQmV5b25kIGFwcHJveGltYXRlbHkgMTAgY2xhc3NlcyBpdCBiZWNvbWVzIHZlcnkgZGlmZmljdWx0IHRvIGRlc2lnbiBhIHBhbGV0dGUKdGhhdCBwcmVzZXJ2ZXMgdGhlIHNlcGFyYXRpb24gYmV0d2VlbiBjb2xvdXJzIGFsbG93aW5nIGNsZWFyIGNsYXNzCmlkZW50aWZpY2F0aW9uLgoKLS0tCgpgYGB7cn0KbGlicmFyeShzZikKbGlicmFyeSh0bWFwKQpsaWJyYXJ5KGh0dHIpCmxpYnJhcnkoanNvbmxpdGUpCmBgYAoKIyMgQ3JlYXRlIGBzZmAgZGF0YSBmcmFtZSBmcm9tIEdlb1BhY2thZ2UgKEdQS0cpCgpDb21iaW5lIHRoZSBmaWxlIHJlYWRpbmcgYW5kIHNwYXRpYWwgc3Vic2V0dGluZyBieSBib3VuZGluZyBib3guCgpgYGB7cn0KIyBDcmVhdGluZyBib3VuZGluZyBib3gKYmJveCA8LSBzdF9iYm94KGMoeG1pbiA9IDUwMzU2OC4xOTk2LCAKICAgICAgICAgICAgICAgICAgeG1heCA9IDU2MTk1Ny40OTYyLCAKICAgICAgICAgICAgICAgICAgeW1pbiA9IDE1NTg1MC43OTc1LCAKICAgICAgICAgICAgICAgICAgeW1heCA9IDIwMDkzMy45MDI2KSwgCiAgICAgICAgICAgICAgICBjcnMgPSBzdF9jcnMoMjc3MDApKQoKIyBDb252ZXJ0IGludG8gYSAnZ2VvbWV0cnknCmJib3ggPC0gc3RfYXNfc2ZjKGJib3gpCgojIENyZWF0ZSBhbiBzZiBkYXRhLmZyYW1lIG9iamVjdCBmcm9tIHRoZSBHcmVlbnNwYWNlIGZpbGUKIyBDYW4gZG8gc3Vic2V0IHVzaW5nIGJvdW5kaW5nIGJveCBhdCBzYW1lIHRpbWUgYXMgcmVhZCBpbgpvc29ncyA8LSBzdF9yZWFkKCcuLi8uLi9kYXRhL29yZG5hbmNlLXN1cnZleS9vcy1vcGVuLWdyZWVuc3BhY2UtZ2IuZ3BrZycsCiAgICAgICAgICAgICAgICAgbGF5ZXIgPSAnZ3JlZW5zcGFjZV9zaXRlJywKICAgICAgICAgICAgICAgICB3a3RfZmlsdGVyID0gc3RfYXNfdGV4dChiYm94KSkgICMgU3Vic2V0IHRoZSBkYXRhIHRvIEdyZWF0ZXIgTG9uZG9uCmBgYAoKIyMgU3Vic2V0IGRhdGEgZnJhbWUgYnkgZnVuY3Rpb24KClJlZHVjZSB0aGUgbnVtYmVyIG9mIGZ1bmN0aW9uIGNhdGVnb3JpZXMgdG8gc3VwcG9ydCBxdWFsaXRhdGl2ZSBzdHlsaW5nIGNvbG91cgpwYWxldHRlIGludGVncmF0aW9uLgoKYGBge3J9CiMgU3Vic2V0IGRhdGEgZnJhbWUgYnkgZnVuY3Rpb24sIGV4Y2x1ZGluZyAnUGxheSBTcGFjZScgYW5kICdUZW5uaXMgQ291cnQnCm9zb2dzX2ZpbHRlcmVkIDwtIG9zb2dzWyFvc29ncyRmdW5jdGlvbi4gJWluJSBjKCdQbGF5IFNwYWNlJywgJ1Rlbm5pcyBDb3VydCcpLCBdCmBgYAoKYGBge3J9CiMgTGlzdCB1bmlxdWUgZnVuY3Rpb24gdmFsdWVzCnVuaXF1ZShvc29nc19maWx0ZXJlZCRmdW5jdGlvbi4pCmBgYAoKYGBge3J9CiMgQ291bnQgbnVtYmVyIG9mIHVuaXF1ZSBmdW5jdGlvbiB2YWx1ZXMKbGVuZ3RoKHVuaXF1ZShvc29nc19maWx0ZXJlZCRmdW5jdGlvbi4pKQpgYGAKCiMjIE9TIE1hcHMgQVBJIFpYWSByZXNvdXJjZQoKYGBge3J9CiMgT1MgTWFwcyBBUEkgbGF5ZXIKIyBFeGFtcGxlIHVzZXMgTGlnaHQgU3R5bGUgaW4gV2ViIE1lcmNhdG9yIChFUFNHOjM4NTcpIHByb2plY3Rpb24KbGF5ZXIgPC0gJ0xpZ2h0XzM4NTcnCgojIE9TIERhdGEgSHViIHByb2plY3QgQVBJIGtleQprZXkgPC0gJzdVVFhNTVdzR2pqSXpjQm1MZEFHbk1PNldFQVFpOU5nJwpgYGAKCmBgYHtyfQojIERlZmluZSB0aGUgdGlsZSBzZXJ2ZXIgcGFyYW1ldGVycwp1cmwgPC0gcGFzdGUwKCdodHRwczovL2FwaS5vcy51ay9tYXBzL3Jhc3Rlci92MS96eHkvJywgbGF5ZXIsCiAgICAgICAgICAgICAgJy97en0ve3h9L3t5fS5wbmc/a2V5PScsIGtleSkKYGBgCgojIyBPUyBHZW9EYXRhVml6IGNvbG91ciBwYWxldHRlcwoKVGhlIE9TIFtHZW9EYXRhVml6CnRvb2xraXRdKGh0dHBzOi8vZ2l0aHViLmNvbS9PcmRuYW5jZVN1cnZleS9HZW9EYXRhVml6LVRvb2xraXQvdHJlZS9tYXN0ZXIvQ29sb3VycykKcHJvdmlkZXMgcXVhbGl0YXRpdmUsIHNlcXVlbnRpYWwsIGFuZCBkaXZlcmdpbmcgY29sb3VyIHBhbGV0dGVzIHRvIHN1cHBvcnQgR0RWCmFwcGxpY2F0aW9ucy4KCmBgYHtyfQojIEdEViBjb2xvdXIgcGFsZXR0ZXMgSlNPTiBmaWxlCmdkdiA8LSAnaHR0cHM6Ly9yYXcuZ2l0aHVidXNlcmNvbnRlbnQuY29tL09yZG5hbmNlU3VydmV5L0dlb0RhdGFWaXotVG9vbGtpdC9tYXN0ZXIvQ29sb3Vycy9HRFYtY29sb3VyLXBhbGV0dGVzLXYwLjcuanNvbicKCiMgTWFrZSBIVFRQIEdFVCByZXF1ZXN0IGFuZCBkZWNvZGUgSlNPTgpnZHZfanNvbiA8LSBHRVQodXJsID0gZ2R2KQpnZHZfanNvbiA8LSBmcm9tSlNPTihjb250ZW50KGdkdl9qc29uKSkKCiMgR2V0IGNvbG91ciBoZXggdmFsdWVzCmdkdl9xdWFsIDwtIHVubGlzdChnZHZfanNvbiRxdWFsaXRhdGl2ZSRsb29rdXApCgojIFNob3cgYW4gZXhhbXBsZSBvZiB0aGUgY29sb3VycwooaW1hZ2UoMTpsZW5ndGgoZ2R2X3F1YWwpLCAxLCBhcy5tYXRyaXgoMTpsZW5ndGgoZ2R2X3F1YWwpKSwgCiAgICAgIGNvbCA9IGdkdl9xdWFsLAogICAgICB4bGFiPSIiLCB5bGFiID0gIiIsIHhheHQgPSAibiIsIHlheHQgPSAibiIsIGJ0eSA9ICJuIikpCmBgYAoKIyMgUGxvdCBkYXRhIGZyYW1lIG9udG9wIG9mIGludGVyYWN0aXZlIG1hcAoKRW1wbG95IGNhdGVnb3JpY2FsIHN0eWxpbmcgdmlhIE9TIEdlb0RhdGFWaXogKEdEVikgcXVhbGl0YXRpdmUgY29sb3VyIHBhbGV0dGUuCgpgYGB7cn0KIyBHZW5lcmF0ZSBhIGJhc2ljIHBsb3Qgb2YgdGhlIGZlYXR1cmVzCnAgPC0gdG1fc2hhcGUob3NvZ3NfZmlsdGVyZWQpICsKICAgICAgdG1fcG9seWdvbnMoJ2Z1bmN0aW9uLicsIAogICAgICAgICAgICAgICAgICBwYWwgPSBnZHZfcXVhbCwKICAgICAgICAgICAgICAgICAgcG9wdXAudmFycyA9IEZBTFNFKQpgYGAKCmBgYHtyLCBmaWcud2lkdGggPSAxMCwgZmlnLmhlaWdodCA9IDEwfQojIENoYW5nZSBwbG90dGluZyBtb2RlIGZyb20gc3RhdGljIHRvIGludGVyYWN0aXZlCnRtYXBfbW9kZSgndmlldycpCgojIENvbWJpbmUgdGhlIGZlYXR1cmVzIGFuZCBiYXNlIG1hcApmaW5hbF9wbG90IDwtIHAgKwogICAgICAgICAgICAgICAgdG1fYmFzZW1hcChzZXJ2ZXIgPSB1cmwpCgpmaW5hbF9wbG90CmBgYAoKYGBge3J9CiMgQ2hhbmdlIGJhY2sgdG8gdGhlIHN0YXRpYyBwbG90dGluZyBtb2RlCnRtYXBfbW9kZSgncGxvdCcpCmBgYAo=